﻿using System;
using System.IO;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Threading;
using System.Runtime.InteropServices;
//using triangleRT_CLI;
namespace Gemren
{
    public partial class Form1 : Form
    {
        const string OutputDoubleFormat = "0.000";
        IFormatProvider DecimalPoint = System.Globalization.CultureInfo.InvariantCulture;
        bool StringToDouble(string str, out double val)
        {
            return double.TryParse(str, System.Globalization.NumberStyles.Float, DecimalPoint, out val);
        }
        System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
        public void swStart()
        {
            sw.Restart();
            statusLabel.Text = "Working...";
        }
        public void swStop(string mesg)
        {
            sw.Stop();
            statusLabel.Text =  mesg + sw.ElapsedMilliseconds.ToString();
        }

        public Form1()
        {
            InitializeComponent();
            openFileDialog1.InitialDirectory = Directory.GetCurrentDirectory();
        }
        public void Deselect()
        {
            SelectedWindow = null;
            SaveImgBtn.Enabled = false;
            RefineBtn.Enabled = false;
            SetCamBtn.Enabled = false;

            GetConfig();
        }
        private void LoadBtn_Click(object sender, EventArgs e)
        {
            if (openFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                string file = openFileDialog1.FileName;
                if (File.Exists(file))
                {
                    statusLabel.Text = "Loading... Please wait.";
                    string dir = Path.GetDirectoryName(file);
                    Directory.SetCurrentDirectory(dir);
                    openFileDialog1.InitialDirectory = dir;
                    SelectedWindow = new FormPreview(this, Path.GetFileName(file));
                    GetConfig();
                }
                else MessageBox.Show("file not found");
            }
        }
        private void SaveImgBtn_Click(object sender, EventArgs e)
        {
            if (SelectedWindow!=null && saveFileDialog1.ShowDialog() == System.Windows.Forms.DialogResult.OK)
            {
                   
                SelectedWindow.SaveImage(saveFileDialog1.FileName);
            }
        }
        public void AddToListBox([MarshalAs(UnmanagedType.LPStr)] string name, int type, [MarshalAs(UnmanagedType.LPStr)] string value)
        {//callback for getProperties
            listBox1.Items.Add(new ConfigItem(name,type, value));
            //interactive fields
            if (name == "exposition") trackBar1.Value = (int)(5 * double.Parse(value));
            else if (name == "camera.pos")
            {
                char[] delim = { ' ' };
                string[] crd = value.Split(delim, 3);
                camX.Text = crd[0];
                camY.Text = crd[1];
                camZ.Text = crd[2];
            }
            else if (name == "camera.dir")
            {
                radioButton1.Checked = true;
                char[] delim = { ' ' };
                string[] crd = value.Split(delim, 3);
                dirX.Text = crd[0];
                dirY.Text = crd[1];
                dirZ.Text = crd[2];
            }
        }
        public void SelectMaterial(string Name)
        {
            for (int i = 0; i < listBox1.Items.Count; ++i)
            {
                ConfigItem ci = listBox1.Items[i] as ConfigItem;
                if (ci.IsPrefixed("scene."+Name+"."))
                {
                    listBox1.SelectedIndex = i;
                    return;
                }
            }
        }
        private void WidthBox_TextChanged(object sender, EventArgs e)
        {

        }
        public void FocusWindow(FormPreview wnd)
        {
            if (SelectedWindow != wnd)
            {
                SelectedWindow = wnd;
                SaveImgBtn.Enabled = true;
                RefineBtn.Enabled = true;
                SetCamBtn.Enabled = true;
                GetConfig();
            }
        }
        FormPreview SelectedWindow = null;


        private void RenderBtn_Click(object sender, EventArgs e)
        {
            //if (SelectedWindow != null)
            
        //    SelectedWindow.Render(int.Parse(WidthBox.Text), int.Parse(HeightBox.Text), false);
        }

        public void SetCameraPos(double cx, double cy, double cz)
        {
            camX.Text = cx.ToString(OutputDoubleFormat, DecimalPoint);
            camY.Text = cy.ToString(OutputDoubleFormat, DecimalPoint);
            camZ.Text = cz.ToString(OutputDoubleFormat, DecimalPoint);
        }
        public void SetCameraDir(double dx, double dy, double dz)
        {
            if (radioButton2.Checked)
                {
                    double cx, cy, cz;
                    if (StringToDouble(camX.Text, out cx) && StringToDouble(camX.Text, out cy) && StringToDouble(camX.Text, out cz))
                    {
                        dx += cx;
                        dy += cy;
                        dz += cz;
                    }
                    else return;
                }
            dirX.Text = dx.ToString(OutputDoubleFormat, DecimalPoint);
            dirY.Text = dy.ToString(OutputDoubleFormat, DecimalPoint);
            dirZ.Text = dz.ToString(OutputDoubleFormat, DecimalPoint);
        }
        private void SetCamBtn_Click(object sender, EventArgs e)
        {
            if (SelectedWindow != null)
            {
                try
                {

                    double cx = double.Parse(camX.Text);
                    double cy = double.Parse(camY.Text);
                    double cz = double.Parse(camZ.Text);
                    double dx = double.Parse(dirX.Text);
                    double dy = double.Parse(dirY.Text);
                    double dz = double.Parse(dirZ.Text);
                    if (radioButton2.Checked)
                    {
                        dx -= cx;
                        dy -= cy;
                        dz -= cz;
                    }

                    SelectedWindow.SetCam(cx, cy, cz, dx, dy, dz);
                }
                catch(Exception ex)
                {
                    MessageBox.Show("Error: invalid values.\n"+ex.Message);
                }
            }
        }
         
        private void trackBar1_Scroll(object sender, EventArgs e)
        {
            if (SelectedWindow != null)
                SelectedWindow.SetExposition(0.2*trackBar1.Value);

        }

        private void button1_Click(object sender, EventArgs e)
        {
            if (SelectedWindow != null)
                SelectedWindow.Toggle();
        }

       
        private void GetConfig(int index = 0)
        {
            listBox1.Items.Clear();
            propertyValue.Text = "";
            if (SelectedWindow!=null) SelectedWindow.GetProperties(AddToListBox);
            if(index<listBox1.Items.Count)
              listBox1.SelectedIndex = index;
        }
        private void Set_Click(object sender, EventArgs e)
        {
            try
            {
                ConfigItem item = listBox1.SelectedItem as ConfigItem;
                int index = listBox1.SelectedIndex;
                if (SelectedWindow != null && item != null)
                {
                    item.value = propertyValue.Text;
                    switch (item.type)
                    {
                        case 0: SelectedWindow.SetInt(item.name, int.Parse(item.value));
                            break;

                        case 1: SelectedWindow.SetString(item.name, item.value);
                            break;

                        case 2: SelectedWindow.SetFloat(item.name, float.Parse(item.value));
                            break;

                        case 3: SelectedWindow.SetBool(item.name, bool.Parse(item.value));
                            break;

                    }
                    GetConfig(index);
                }
            }
            catch (Exception ex) 
            {
                MessageBox.Show("Error: " + ex.Message /*bad number format etc */ );
            }
        }

        private void listBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (listBox1.SelectedItem != null)
            {
                propertyValue.Enabled = true;
                propertyValue.Text = ((ConfigItem)listBox1.SelectedItem).value;
            }
            else
            {
                propertyValue.Text = "";
                propertyValue.Enabled = false;
            }
        }

        private void saveFileDialog1_FileOk(object sender, CancelEventArgs e)
        {

        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }


    }

    public class ConfigItem
    { //to be used in listbox
        public string name;
        public int type;
        public string value;
        static string[] stypes = { "(int)", "(string)", "(float)", "(bool)" };
        public ConfigItem(string Name, int Type, string Value)
        {
            name = Name;
            type = Type;
            value = Value;
        }
        public override string ToString()
        {
            return name + " = " + stypes[type] + " " + value;
        }
        public bool IsPrefixed(string prefix)
        {
            if (name.Length < prefix.Length) return false;
            for (int i = 0; i < prefix.Length; ++i)
            {
                if (name[i] != prefix[i]) return false;
            }
            return true;
        }
    }
}
